package jers.impl;

import java.rmi.Naming;
import java.rmi.RemoteException;

import jers.JERS;
import jers.Manager;
import jers.Service;
import jers.util.FileServer;
import jers.util.SecurityUtil;
import jers.util.Utility;


/**
 * Clsse responsavel por instanciar os servicos remotos.
 * A instancia deve ser obtida pelo metodo estatico {@link #getService()}.
 * <br>
 * Esta implementa o lado do cliente no servico RMI.

 * @see {@link SystemFactory}, {@link Service} 
 * 
 * @author 
 * 		<a href="mailto:felipe.zappala@gmail.com">
 * 			Luis Felipe Zappala
 * 		</a> [ <a href="http://lncc.br/ist">ISTCC-P</a> / 2009 ]
 */
final class RemoteManager implements Manager {
	
	/**
	 * Retorna uma instancia do objeto {@link Service}
	 * Esta instancia e um proxy para o objeto remoto real.
	 *  
	 * @return
	 * 		A instancia do stub, o objeto proxy remoto do servico.
	 * @throws 
	 * 		RemoteException caso ocorra algum erro remoto.
	 */
	public Service getService(String server) throws RemoteException {
		JERS.log.info(Utility.concat("[RemoteManager] ",
				"Getting instance server: ", server));
		
		if (server == null) {
			throw new RemoteException("Parameter server is null");
		}
		
		//
		// Configura o gerenciador de segurancao para usar o RMISecurityManager
		//
		if (System.getSecurityManager() == null) {
			SecurityUtil.setupSecurityPolicy();
			SecurityUtil.setupSecurityManager();
		}
		
		try {
			//
			// Inicia o servidor do cliente para o download dinamico de classes
			//
			startClientHTTPFileServer();
			
			//
			// Obtem o endereco URI do servidor RMI
			//
			String uri = getRMIAddress(server);
			
			JERS.log.info("[RemoteManager] Server RMI address: ", uri);
			
			//
			// Obtendo o stub, a instancia proxy, do objeto remoto.
			//
			Service service = (Service) Naming.lookup(uri);
			
			JERS.log.info("[RemoteManager] Getted instance with success!");
			
			return new RemoteServiceProxy(service);
			
		} catch (Exception e) {
			String msg = Utility.concat("[RemoteManager] ERROR: ",
			e.getClass().getSimpleName(), " - ", e.getMessage()); 
			JERS.log.error(msg, e);
			throw new RemoteException(msg, e);
		}
	}

	/**
	 * Obtem a URI RMI para o servidor passado.
	 * 
	 * @param 
	 * 		server - O dominio ou IP e porta do servidor remoto. 
	 * @return 
	 * 		A URI do RMI
	 * @throws 
	 * 		RemoteException caso ocorra algum erro.
	 */
	protected String getRMIAddress(String server) throws RemoteException {
		String service = JERS.SERVICE_NAME;
		String address = "";
		int port = 0;
		
		try {
			String[] addr = server.split("\\:");
			address = addr[0];
			port = Integer.parseInt(addr[1]);
			
		} catch (ArrayIndexOutOfBoundsException a) {
			boolean useActivation = Boolean.valueOf(JERS.config
					.getProperty("jers.service.activation.use"));
			
			if (useActivation) {
				port = JERS.ACTIVATION_PORT;
			} else {
				port = JERS.SERVICE_PORT;
			}
		} catch (Exception e) {
			throw new RemoteException(Utility.concat(
					"Parameter server is invalid or unknown: ",
					e.getMessage(), e));
		}
		
		String uri = Utility.concat("rmi://", address, ":", port, "/", service);
		
		return uri;
	}
	
	private void startClientHTTPFileServer() {
		String codeBase = JERS.config.getProperty("java.rmi.server.codebase");
		if (!Utility.validate(codeBase)) {
			FileServer fileServer = JERS.factory.newFileServer();
			fileServer.start();
			codeBase = fileServer.getAddress();
		}
		// Configura o caminho base para download dos stubs do RMI
		System.setProperty("java.rmi.server.codebase", codeBase);
	}
	
}
